package laba12.src.laba5;
//package laba5;- это должно быть

import interfaces.task5.ArrayCollection;
import interfaces.task5.ArrayIterator;
import static java.lang.System.arraycopy;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.NoSuchElementException;

/**
 *
 * @author yakimovich
 */
public class ArrayCollectionImpl<E extends Object> implements ArrayCollection {

    private Object[] data;
    private int size;

    /**
     * Create ArrayCollectionImpl with initial capacity
     *
     * @param initialCapacity
     */
    public ArrayCollectionImpl(int initialCapacity) {
        if (initialCapacity < 0) {
            throw new IllegalArgumentException("Illegal Capacity: "
                    + initialCapacity);
        }
        this.data = new Object[initialCapacity];
        size = 0;
    }

    /**
     * Create initialCapacity by default
     */
    public ArrayCollectionImpl() {
        this(0);
    }

    /**
     *
     * @return data array of ArrayCollectionImpl
     */
    @Override
    public Object[] getArray() {
        return data;
    }

    /**
     * Set data array for ArrayCollectionImpl
     *
     * @param es - array for set
     */
    @Override
    public void setArray(Object[] es) {
        this.data = es;
        size = 0;
        for (int i = data.length - 1; i >= 0; i--) {
            if (data[i] != null) {
                size = i + 1;
                return;
            }
        }
    }

    @Override
    public int size() {
        return size;
    }

    @Override
    public boolean isEmpty() {
        return size == 0;
    }

    @Override
    public boolean contains(Object o) {
        int index = -1;
        if (o == null) {
            for (int i = 0; i < size; i++) {
                if (data[i] == null) {
                    index = i;
                }
            }
        } else {
            for (int i = 0; i < size; i++) {
                if (o.equals(data[i])) {
                    index = i;
                }
            }
        }
        return index >= 0;
    }

    @Override
    public Iterator iterator() {
        return new ArrayIteratorImpl();
    }

    private class ArrayIteratorImpl implements ArrayIterator {

        private int cursor;
        int lastRet = -1; // index of last element returned; -1 if no such

        private ArrayIteratorImpl() {
            cursor = 0;
        }

        @Override
        public Object[] getArray() {
            return data;
        }

        @Override
        public boolean hasNext() {
            return cursor < size;
        }

        @Override
        public Object next() {
            if (cursor < size) {
                lastRet = cursor;
                return data[cursor++];
            } else {
                throw new NoSuchElementException();
            }
        }

        @Override
        public void remove() {
            if (lastRet < 0 || cursor >= size) {
                throw new IllegalStateException();
            }

            Object[] tmp = new Object[data.length];
            arraycopy(data, 0, tmp, 0, cursor);
            arraycopy(data, cursor + 1, tmp, cursor, data.length - cursor - 1);
            size--;
            data = tmp;

        }
    }

    @Override
    public Object[] toArray() {
        return Arrays.copyOf(data, size);
    }

    @Override
    public Object[] toArray(Object[] a) {
        if (a.length < size) {
            return Arrays.copyOf(data, size, a.getClass());
        }
        System.arraycopy(data, 0, a, 0, size);
        if (a.length > size) {
            a[size] = null;
        }
        return a;
    }

    @Override
    public boolean add(Object e) {
        Object[] tmp = new Object[size + 1];
        arraycopy(data, 0, tmp, 0, size);
        tmp[size] = e;
        this.data = tmp;
        size++;
        return true;
    }

    @Override
    public boolean remove(Object o) {
        boolean ifRemove = false;
        Object[] tmp = Arrays.copyOf(data, data.length - 1);

        if (o == null) {
            for (int index = 0; index < size; index++) {
                if (data[index] == null) {
                    arraycopy(data, index + 1, tmp, index, tmp.length - index);
                    --size;
                    data = tmp;
                    ifRemove = true;
                }
            }
        } else {
            for (int index = 0; index < size; index++) {
                if (o.equals(data[index])) {
                    arraycopy(data, index + 1, tmp, index, tmp.length - index);
                    --size;
                    data = tmp;
                    ifRemove = true;
                }
            }
        }
        return ifRemove;
    }

    @Override
    public boolean containsAll(Collection c) {
        for (Object e : c) {
            if (!contains(e)) {
                return false;
            }
        }
        return true;
    }

    @Override
    public boolean addAll(Collection c) {
        if (c == this) {
            throw new IllegalArgumentException();
        }
        Object[] a = c.toArray();
        int numNew = a.length;
        data = Arrays.copyOf(data, size + numNew);
        System.arraycopy(a, 0, data, size, numNew);
        size += numNew;
        return numNew != 0;
    }

    @Override
    public boolean removeAll(Collection c) {
        if (c == null) {
            throw new NullPointerException();
        }
        boolean modified = false;
        for (int i = size - 1; i >= 0; i--) {
            if (c.contains(data[i])) {
                remove(data[i]);
                modified = true;
            }
        }
        return modified;
    }

    @Override
    public boolean retainAll(Collection c) {
        if (c == null) {
            throw new NullPointerException();
        }
        boolean modified = false;
        for (int i = size - 1; i >= 0; i--) {
            if (!c.contains(data[i])) {
                remove(data[i]);
                modified = true;
            }
        }
        return modified;
    }

    @Override
    public void clear() {
        data = new Object[0];
        size = 0;
    }
}
